Introduction

This is code for Section 17.2 of Kruschke using a Student t noise distribution. Other than that change, this document is very similar to the one from section 7.1.

Make sure that the two files “HtWtData30.csv” and “HtWtData300.csv” are in your project directory.

Preliminaries

Load necessary packages:

library(tidyverse)
library(rstan)
library(tidybayes)
library(bayesplot)

Set Stan to save compiled code.

rstan_options(auto_write = TRUE)

Set Stan to use parallel processing where possible.

options(mc.cores = parallel::detectCores())

Data

HtWtData30 <- read_csv("HtWtData30.csv")
Rows: 30 Columns: 3── Column specification ─────────────────────────────────────────
Delimiter: ","
dbl (3): male, height, weight
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
HtWtData30
ggplot(HtWtData30, aes(y = weight, x = height)) +
    geom_point()

HtWtData300 <- read_csv("HtWtData300.csv")
Rows: 300 Columns: 3── Column specification ─────────────────────────────────────────
Delimiter: ","
dbl (3): male, height, weight
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
HtWtData300
ggplot(HtWtData300, aes(y = weight, x = height)) +
    geom_point()

Mean center the x variable to get an interpretable intercept. (Kruschke standardizes both variables using z-scores, but that makes the coefficients of the model harder to interpret.)

HtWtData30 <- HtWtData30 %>%
    mutate(height_mc = height - mean(height))
HtWtData30
ggplot(HtWtData30, aes(y = weight, x = height_mc)) +
    geom_point()

HtWtData300 <- HtWtData300 %>%
    mutate(height_mc = height - mean(height))
HtWtData300
ggplot(HtWtData300, aes(y = weight, x = height_mc)) +
    geom_point()

We’re going to run two different examples, so we’ll make two lists.

stan_data_30 <- list(N = NROW(HtWtData30),
                     y = HtWtData30$weight,
                     x = HtWtData30$height_mc)
stan_data_300 <- list(N = NROW(HtWtData300),
                      y = HtWtData300$weight,
                      x = HtWtData300$height_mc)

Prior

Simulation code

data {
    int<lower = 0> N;
    vector<lower = 0>[N] y;
    vector[N] x;
}
generated quantities {
    real nu;
    real beta0;
    real beta1;
    vector[N] mu;
    real<lower = 0> sigma;
    real y_sim[N];
    
    nu = gamma_rng(2, 0.1);       // default prior for df
    beta0 = normal_rng(150, 25);  // Intercept between 100 and 200
    beta1 = normal_rng(0, 5);    // -10 to 10 lbs per inch
    mu = beta0 + beta1 * x;       // linear model
    sigma = exponential_rng(1.0/100.0); // sd of 100 lbs
    y_sim = student_t_rng(nu, mu, sigma);
}
fit_HtWt30_robust_prior <- sampling(HtWt_robust_prior,
                                    data = stan_data_30,
                                    chains = 1,
                                    algorithm = "Fixed_param",
                                    seed = 11111,
                                    refresh = 0)
samples_HtWt30_robust_prior <- tidy_draws(fit_HtWt30_robust_prior)
samples_HtWt30_robust_prior

Examine prior

mcmc_hist(samples_HtWt30_robust_prior,
          pars = c("nu", "sigma", "beta0", "beta1"))

mcmc_pairs(fit_HtWt30_robust_prior,
           pars = c("nu", "sigma", "beta0", "beta1"))
Warning: Only one chain in 'x'. This plot is more useful with multiple chains.

ggplot(HtWtData30, aes(y = weight, x = height_mc)) +
    geom_point() +
    geom_abline(data = samples_HtWt30_robust_prior,
                aes(intercept = beta0, slope = beta1),
                alpha = 0.05)

Prior predictive distribution

y_sim_HtWt30_prior <- samples_HtWt30_robust_prior %>%
    select(starts_with("y_sim")) %>%
    as.matrix()
ppd_intervals(ypred = y_sim_HtWt30_prior,
              x = HtWtData30$height_mc)

Model

data {
    int<lower = 0> N;
    vector<lower = 0>[N] y;
    vector[N] x;
}
parameters {
    real nu;
    real beta0;
    real beta1;
    real<lower = 0> sigma;
}
transformed parameters {
    vector[N] mu;
    mu = beta0 + beta1 * x;   // linear model
}
model {
    nu ~ gamma(2, 0.1);       // default prior for df
    beta0 ~ normal(150, 25);  // Intercept between 100 and 200
    beta1 ~ normal(0, 5);    // -10 to 10 lbs per inch
    sigma ~ exponential(1.0/100.0); // sd of 100 lbs
    y ~ student_t(nu, mu, sigma);
}
generated quantities {
    real y_sim[N];
    y_sim = student_t_rng(nu, mu, sigma);
}
fit_HtWt30_robust <- sampling(HtWt_robust,
                              data = stan_data_30,
                              seed = 11111,
                              refresh = 0)
Warning: There were 615 divergent transitions after warmup. See
https://mc-stan.org/misc/warnings.html#divergent-transitions-after-warmup
to find out why this is a problem and how to eliminate them.Warning: Examine the pairs() plot to diagnose sampling problems
samples_HtWt30_robust <- tidy_draws(fit_HtWt30_robust)
samples_HtWt30_robust

Model diagnostics

stan_trace(fit_HtWt30_robust,
           pars = c("nu", "sigma", "beta0", "beta1"))

mcmc_acf(fit_HtWt30_robust,
         pars = c("nu", "sigma", "beta0", "beta1"))

Model summary

print(fit_HtWt30_robust,
      pars = c("nu", "beta0", "beta1", "sigma"))
Inference for Stan model: anon_model.
4 chains, each with iter=2000; warmup=1000; thin=1; 
post-warmup draws per chain=1000, total post-warmup draws=4000.

        mean se_mean    sd   2.5%    25%    50%    75%  97.5%
nu     18.37    0.45 12.53   3.55   9.07  15.20  24.36  49.69
beta0 152.76    0.11  4.86 143.53 149.55 152.67 155.93 162.65
beta1   4.25    0.03  1.23   1.79   3.48   4.26   5.07   6.77
sigma  25.74    0.13  4.37  18.22  22.69  25.30  28.35  35.36
      n_eff Rhat
nu      776 1.01
beta0  1796 1.00
beta1  1399 1.00
sigma  1075 1.00

Samples were drawn using NUTS(diag_e) at Sat May 13 23:49:01 2023.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at 
convergence, Rhat=1).

Model visualization

mcmc_areas(fit_HtWt30_robust, pars = "nu")

mcmc_areas(fit_HtWt30_robust, pars ="sigma")

mcmc_areas(fit_HtWt30_robust, pars ="beta0")

mcmc_areas(fit_HtWt30_robust, pars = "beta1")

pairs(fit_HtWt30_robust,
      pars = c("nu", "sigma", "beta0", "beta1"))

Posterior predictive check

y_sim_HtWt30_robust <- samples_HtWt30_robust %>%
    select(starts_with("y_sim")) %>%
    as.matrix()
ggplot(HtWtData30, aes(y = weight, x = height_mc)) +
    geom_point() +
    geom_abline(data = samples_HtWt30_robust,
                aes(intercept = beta0, slope = beta1),
                alpha = 0.01) +
    geom_abline(data = samples_HtWt30_robust,
                aes(intercept = mean(beta0), slope = mean(beta1)),
                color = "blue", linewidth = 2)

Compare to standard linear regression.

ggplot(HtWtData30, aes(y = weight, x = height_mc)) +
    geom_point() +
    geom_abline(data = samples_HtWt30_robust,
                aes(intercept = beta0, slope = beta1),
                alpha = 0.01) +
    geom_abline(data = samples_HtWt30_robust,
                aes(intercept = mean(beta0), slope = mean(beta1)),
                color = "blue", linewidth = 2) +
    geom_smooth(method = lm, color = "red", linewidth = 2)

ppc_intervals(y = HtWtData30$weight,
              x = HtWtData30$height_mc,
              yrep = y_sim_HtWt30_robust,
              prob = 0.68,
              prob_outer = 0.95)

ppc_hist(y = HtWtData30$weight,
         yrep = y_sim_HtWt30_robust[1:19, ])

ppc_boxplot(y = HtWtData30$weight,
            yrep = y_sim_HtWt30_robust[1:10, ],
            notch = FALSE)

ppc_dens_overlay(y = HtWtData30$weight,
                 yrep = y_sim_HtWt30_robust[1:50, ])

ppc_stat_2d(y = HtWtData30$weight,
            yrep = y_sim_HtWt30_robust)

The model with 300 observations

fit_HtWt300_robust <- sampling(HtWt_robust,
                               data = stan_data_300,
                               seed = 11111,
                               refresh = 0)
samples_HtWt300_robust <- tidy_draws(fit_HtWt300_robust)
samples_HtWt300_robust

Model diagnostics

stan_trace(fit_HtWt300_robust,
           pars = c("nu", "sigma", "beta0", "beta1"))

mcmc_acf(fit_HtWt300_robust,
         pars = c("nu", "sigma", "beta0", "beta1"))

Model summary

print(fit_HtWt300_robust,
      pars = c("nu", "beta0", "beta1", "sigma"))
Inference for Stan model: anon_model.
4 chains, each with iter=2000; warmup=1000; thin=1; 
post-warmup draws per chain=1000, total post-warmup draws=4000.

        mean se_mean   sd   2.5%    25%    50%    75%  97.5%
nu      5.67    0.05 1.77   3.26   4.44   5.32   6.49  10.22
beta0 156.32    0.03 1.68 153.09 155.19 156.28 157.45 159.73
beta1   4.43    0.01 0.40   3.62   4.15   4.43   4.71   5.20
sigma  24.16    0.04 1.68  20.94  22.99  24.14  25.31  27.51
      n_eff Rhat
nu     1324    1
beta0  2508    1
beta1  3408    1
sigma  1766    1

Samples were drawn using NUTS(diag_e) at Sat May 13 23:49:57 2023.
For each parameter, n_eff is a crude measure of effective sample size,
and Rhat is the potential scale reduction factor on split chains (at 
convergence, Rhat=1).

Model visualization

mcmc_areas(fit_HtWt300_robust, pars = "nu")

mcmc_areas(fit_HtWt300_robust, pars ="sigma")

mcmc_areas(fit_HtWt300_robust, pars ="beta0")

mcmc_areas(fit_HtWt300_robust, pars = "beta1")

pairs(fit_HtWt300_robust,
      pars = c("nu", "sigma", "beta0", "beta1"))

Posterior predictive check

y_sim_HtWt300_robust <- samples_HtWt300_robust %>%
    select(starts_with("y_sim")) %>%
    as.matrix()
ggplot(HtWtData300, aes(y = weight, x = height_mc)) +
    geom_point() +
    geom_abline(data = samples_HtWt300_robust,
                aes(intercept = beta0, slope = beta1),
                alpha = 0.01) +
    geom_abline(data = samples_HtWt300_robust,
                aes(intercept = mean(beta0), slope = mean(beta1)),
                color = "blue", linewidth = 2)

Compare to standard linear regression.

ggplot(HtWtData300, aes(y = weight, x = height_mc)) +
    geom_point() +
    geom_abline(data = samples_HtWt300_robust,
                aes(intercept = beta0, slope = beta1),
                alpha = 0.01) +
    geom_abline(data = samples_HtWt300_robust,
                aes(intercept = mean(beta0), slope = mean(beta1)),
                color = "blue", linewidth = 2) +
    geom_smooth(method = lm, color = "red", linewidth = 2)

ppc_intervals(y = HtWtData300$weight,
              x = HtWtData300$height_mc,
              yrep = y_sim_HtWt300_robust,
              prob = 0.68,
              prob_outer = 0.95)

ppc_hist(y = HtWtData300$weight,
         yrep = y_sim_HtWt300_robust[1:19, ])

ppc_boxplot(y = HtWtData300$weight,
            yrep = y_sim_HtWt300_robust[1:10, ],
            notch = FALSE)

ppc_dens_overlay(y = HtWtData300$weight,
                 yrep = y_sim_HtWt300_robust[1:50, ])

ppc_stat_2d(y = HtWtData300$weight,
            yrep = y_sim_HtWt300_robust)

LS0tDQp0aXRsZTogIjE3LjI6IFJvYnVzdCByZWdyZXNzaW9uIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQojIyBJbnRyb2R1Y3Rpb24NCg0KVGhpcyBpcyBjb2RlIGZvciBTZWN0aW9uIDE3LjIgb2YgS3J1c2Noa2UgdXNpbmcgYSBTdHVkZW50IHQgbm9pc2UgZGlzdHJpYnV0aW9uLiBPdGhlciB0aGFuIHRoYXQgY2hhbmdlLCB0aGlzIGRvY3VtZW50IGlzIHZlcnkgc2ltaWxhciB0byB0aGUgb25lIGZyb20gc2VjdGlvbiA3LjEuDQoNCk1ha2Ugc3VyZSB0aGF0IHRoZSB0d28gZmlsZXMgIkh0V3REYXRhMzAuY3N2IiBhbmQgIkh0V3REYXRhMzAwLmNzdiIgYXJlIGluIHlvdXIgcHJvamVjdCBkaXJlY3RvcnkuDQoNCg0KIyMgUHJlbGltaW5hcmllcw0KDQpMb2FkIG5lY2Vzc2FyeSBwYWNrYWdlczoNCg0KYGBge3J9DQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocnN0YW4pDQpsaWJyYXJ5KHRpZHliYXllcykNCmxpYnJhcnkoYmF5ZXNwbG90KQ0KYGBgDQoNClNldCBTdGFuIHRvIHNhdmUgY29tcGlsZWQgY29kZS4NCg0KYGBge3J9DQpyc3Rhbl9vcHRpb25zKGF1dG9fd3JpdGUgPSBUUlVFKQ0KYGBgDQoNClNldCBTdGFuIHRvIHVzZSBwYXJhbGxlbCBwcm9jZXNzaW5nIHdoZXJlIHBvc3NpYmxlLg0KDQpgYGB7cn0NCm9wdGlvbnMobWMuY29yZXMgPSBwYXJhbGxlbDo6ZGV0ZWN0Q29yZXMoKSkNCmBgYA0KDQoNCiMjIERhdGENCg0KYGBge3J9DQpIdFd0RGF0YTMwIDwtIHJlYWRfY3N2KCJIdFd0RGF0YTMwLmNzdiIpDQpIdFd0RGF0YTMwDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoSHRXdERhdGEzMCwgYWVzKHkgPSB3ZWlnaHQsIHggPSBoZWlnaHQpKSArDQogICAgZ2VvbV9wb2ludCgpDQpgYGANCg0KYGBge3J9DQpIdFd0RGF0YTMwMCA8LSByZWFkX2NzdigiSHRXdERhdGEzMDAuY3N2IikNCkh0V3REYXRhMzAwDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoSHRXdERhdGEzMDAsIGFlcyh5ID0gd2VpZ2h0LCB4ID0gaGVpZ2h0KSkgKw0KICAgIGdlb21fcG9pbnQoKQ0KYGBgDQoNCk1lYW4gY2VudGVyIHRoZSB4IHZhcmlhYmxlIHRvIGdldCBhbiBpbnRlcnByZXRhYmxlIGludGVyY2VwdC4gKEtydXNjaGtlIHN0YW5kYXJkaXplcyBib3RoIHZhcmlhYmxlcyB1c2luZyB6LXNjb3JlcywgYnV0IHRoYXQgbWFrZXMgdGhlIGNvZWZmaWNpZW50cyBvZiB0aGUgbW9kZWwgaGFyZGVyIHRvIGludGVycHJldC4pDQoNCmBgYHtyfQ0KSHRXdERhdGEzMCA8LSBIdFd0RGF0YTMwICU+JQ0KICAgIG11dGF0ZShoZWlnaHRfbWMgPSBoZWlnaHQgLSBtZWFuKGhlaWdodCkpDQpIdFd0RGF0YTMwDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoSHRXdERhdGEzMCwgYWVzKHkgPSB3ZWlnaHQsIHggPSBoZWlnaHRfbWMpKSArDQogICAgZ2VvbV9wb2ludCgpDQpgYGANCg0KDQpgYGB7cn0NCkh0V3REYXRhMzAwIDwtIEh0V3REYXRhMzAwICU+JQ0KICAgIG11dGF0ZShoZWlnaHRfbWMgPSBoZWlnaHQgLSBtZWFuKGhlaWdodCkpDQpIdFd0RGF0YTMwMA0KYGBgDQoNCmBgYHtyfQ0KZ2dwbG90KEh0V3REYXRhMzAwLCBhZXMoeSA9IHdlaWdodCwgeCA9IGhlaWdodF9tYykpICsNCiAgICBnZW9tX3BvaW50KCkNCmBgYA0KDQpXZSdyZSBnb2luZyB0byBydW4gdHdvIGRpZmZlcmVudCBleGFtcGxlcywgc28gd2UnbGwgbWFrZSB0d28gbGlzdHMuDQoNCmBgYHtyfQ0Kc3Rhbl9kYXRhXzMwIDwtIGxpc3QoTiA9IE5ST1coSHRXdERhdGEzMCksDQogICAgICAgICAgICAgICAgICAgICB5ID0gSHRXdERhdGEzMCR3ZWlnaHQsDQogICAgICAgICAgICAgICAgICAgICB4ID0gSHRXdERhdGEzMCRoZWlnaHRfbWMpDQpzdGFuX2RhdGFfMzAwIDwtIGxpc3QoTiA9IE5ST1coSHRXdERhdGEzMDApLA0KICAgICAgICAgICAgICAgICAgICAgIHkgPSBIdFd0RGF0YTMwMCR3ZWlnaHQsDQogICAgICAgICAgICAgICAgICAgICAgeCA9IEh0V3REYXRhMzAwJGhlaWdodF9tYykNCmBgYA0KDQoNCiMjIFByaW9yDQoNCiMjIyBTaW11bGF0aW9uIGNvZGUNCg0KYGBge3N0YW4sIG91dHB1dC52YXIgPSAiSHRXdF9yb2J1c3RfcHJpb3IiLCBjYWNoZSA9IFRSVUV9DQpkYXRhIHsNCiAgICBpbnQ8bG93ZXIgPSAwPiBOOw0KICAgIHZlY3Rvcjxsb3dlciA9IDA+W05dIHk7DQogICAgdmVjdG9yW05dIHg7DQp9DQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7DQogICAgcmVhbCBudTsNCiAgICByZWFsIGJldGEwOw0KICAgIHJlYWwgYmV0YTE7DQogICAgdmVjdG9yW05dIG11Ow0KICAgIHJlYWw8bG93ZXIgPSAwPiBzaWdtYTsNCiAgICByZWFsIHlfc2ltW05dOw0KICAgIA0KICAgIG51ID0gZ2FtbWFfcm5nKDIsIDAuMSk7ICAgICAgIC8vIGRlZmF1bHQgcHJpb3IgZm9yIGRmDQogICAgYmV0YTAgPSBub3JtYWxfcm5nKDE1MCwgMjUpOyAgLy8gSW50ZXJjZXB0IGJldHdlZW4gMTAwIGFuZCAyMDANCiAgICBiZXRhMSA9IG5vcm1hbF9ybmcoMCwgNSk7ICAgIC8vIC0xMCB0byAxMCBsYnMgcGVyIGluY2gNCiAgICBtdSA9IGJldGEwICsgYmV0YTEgKiB4OyAgICAgICAvLyBsaW5lYXIgbW9kZWwNCiAgICBzaWdtYSA9IGV4cG9uZW50aWFsX3JuZygxLjAvMTAwLjApOyAvLyBzZCBvZiAxMDAgbGJzDQogICAgeV9zaW0gPSBzdHVkZW50X3Rfcm5nKG51LCBtdSwgc2lnbWEpOw0KfQ0KYGBgDQoNCmBgYHtyLCBjYWNoZSA9IFRSVUV9DQpmaXRfSHRXdDMwX3JvYnVzdF9wcmlvciA8LSBzYW1wbGluZyhIdFd0X3JvYnVzdF9wcmlvciwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBzdGFuX2RhdGFfMzAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGFpbnMgPSAxLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWxnb3JpdGhtID0gIkZpeGVkX3BhcmFtIiwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMTExMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZnJlc2ggPSAwKQ0KYGBgDQoNCmBgYHtyfQ0Kc2FtcGxlc19IdFd0MzBfcm9idXN0X3ByaW9yIDwtIHRpZHlfZHJhd3MoZml0X0h0V3QzMF9yb2J1c3RfcHJpb3IpDQpzYW1wbGVzX0h0V3QzMF9yb2J1c3RfcHJpb3INCmBgYA0KDQojIyMgRXhhbWluZSBwcmlvcg0KDQpgYGB7cn0NCm1jbWNfaGlzdChzYW1wbGVzX0h0V3QzMF9yb2J1c3RfcHJpb3IsDQogICAgICAgICAgcGFycyA9IGMoIm51IiwgInNpZ21hIiwgImJldGEwIiwgImJldGExIikpDQpgYGANCg0KYGBge3J9DQptY21jX3BhaXJzKGZpdF9IdFd0MzBfcm9idXN0X3ByaW9yLA0KICAgICAgICAgICBwYXJzID0gYygibnUiLCAic2lnbWEiLCAiYmV0YTAiLCAiYmV0YTEiKSkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChIdFd0RGF0YTMwLCBhZXMoeSA9IHdlaWdodCwgeCA9IGhlaWdodF9tYykpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fYWJsaW5lKGRhdGEgPSBzYW1wbGVzX0h0V3QzMF9yb2J1c3RfcHJpb3IsDQogICAgICAgICAgICAgICAgYWVzKGludGVyY2VwdCA9IGJldGEwLCBzbG9wZSA9IGJldGExKSwNCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDUpDQpgYGANCg0KDQojIyMgUHJpb3IgcHJlZGljdGl2ZSBkaXN0cmlidXRpb24NCg0KYGBge3J9DQp5X3NpbV9IdFd0MzBfcHJpb3IgPC0gc2FtcGxlc19IdFd0MzBfcm9idXN0X3ByaW9yICU+JQ0KICAgIHNlbGVjdChzdGFydHNfd2l0aCgieV9zaW0iKSkgJT4lDQogICAgYXMubWF0cml4KCkNCmBgYA0KDQpgYGB7cn0NCnBwZF9pbnRlcnZhbHMoeXByZWQgPSB5X3NpbV9IdFd0MzBfcHJpb3IsDQogICAgICAgICAgICAgIHggPSBIdFd0RGF0YTMwJGhlaWdodF9tYykNCmBgYA0KDQoNCiMjIE1vZGVsDQoNCmBgYHtzdGFuLCBvdXRwdXQudmFyID0gIkh0V3Rfcm9idXN0IiwgY2FjaGUgPSBUUlVFfQ0KZGF0YSB7DQogICAgaW50PGxvd2VyID0gMD4gTjsNCiAgICB2ZWN0b3I8bG93ZXIgPSAwPltOXSB5Ow0KICAgIHZlY3RvcltOXSB4Ow0KfQ0KcGFyYW1ldGVycyB7DQogICAgcmVhbCBudTsNCiAgICByZWFsIGJldGEwOw0KICAgIHJlYWwgYmV0YTE7DQogICAgcmVhbDxsb3dlciA9IDA+IHNpZ21hOw0KfQ0KdHJhbnNmb3JtZWQgcGFyYW1ldGVycyB7DQogICAgdmVjdG9yW05dIG11Ow0KICAgIG11ID0gYmV0YTAgKyBiZXRhMSAqIHg7ICAgLy8gbGluZWFyIG1vZGVsDQp9DQptb2RlbCB7DQogICAgbnUgfiBnYW1tYSgyLCAwLjEpOyAgICAgICAvLyBkZWZhdWx0IHByaW9yIGZvciBkZg0KICAgIGJldGEwIH4gbm9ybWFsKDE1MCwgMjUpOyAgLy8gSW50ZXJjZXB0IGJldHdlZW4gMTAwIGFuZCAyMDANCiAgICBiZXRhMSB+IG5vcm1hbCgwLCA1KTsgICAgLy8gLTEwIHRvIDEwIGxicyBwZXIgaW5jaA0KICAgIHNpZ21hIH4gZXhwb25lbnRpYWwoMS4wLzEwMC4wKTsgLy8gc2Qgb2YgMTAwIGxicw0KICAgIHkgfiBzdHVkZW50X3QobnUsIG11LCBzaWdtYSk7DQp9DQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7DQogICAgcmVhbCB5X3NpbVtOXTsNCiAgICB5X3NpbSA9IHN0dWRlbnRfdF9ybmcobnUsIG11LCBzaWdtYSk7DQp9DQpgYGANCg0KYGBge3IsIGNhY2hlID0gVFJVRX0NCmZpdF9IdFd0MzBfcm9idXN0IDwtIHNhbXBsaW5nKEh0V3Rfcm9idXN0LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHN0YW5fZGF0YV8zMCwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlZWQgPSAxMTExMSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZnJlc2ggPSAwKQ0KYGBgDQoNCmBgYHtyfQ0Kc2FtcGxlc19IdFd0MzBfcm9idXN0IDwtIHRpZHlfZHJhd3MoZml0X0h0V3QzMF9yb2J1c3QpDQpzYW1wbGVzX0h0V3QzMF9yb2J1c3QNCmBgYA0KDQojIyBNb2RlbCBkaWFnbm9zdGljcw0KDQpgYGB7cn0NCnN0YW5fdHJhY2UoZml0X0h0V3QzMF9yb2J1c3QsDQogICAgICAgICAgIHBhcnMgPSBjKCJudSIsICJzaWdtYSIsICJiZXRhMCIsICJiZXRhMSIpKQ0KYGBgDQoNCmBgYHtyfQ0KbWNtY19hY2YoZml0X0h0V3QzMF9yb2J1c3QsDQogICAgICAgICBwYXJzID0gYygibnUiLCAic2lnbWEiLCAiYmV0YTAiLCAiYmV0YTEiKSkNCmBgYA0KDQoNCiMjIE1vZGVsIHN1bW1hcnkNCg0KYGBge3J9DQpwcmludChmaXRfSHRXdDMwX3JvYnVzdCwNCiAgICAgIHBhcnMgPSBjKCJudSIsICJiZXRhMCIsICJiZXRhMSIsICJzaWdtYSIpKQ0KYGBgDQoNCg0KIyMgTW9kZWwgdmlzdWFsaXphdGlvbg0KDQpgYGB7cn0NCm1jbWNfYXJlYXMoZml0X0h0V3QzMF9yb2J1c3QsIHBhcnMgPSAibnUiKQ0KYGBgDQoNCmBgYHtyfQ0KbWNtY19hcmVhcyhmaXRfSHRXdDMwX3JvYnVzdCwgcGFycyA9InNpZ21hIikNCmBgYA0KDQpgYGB7cn0NCm1jbWNfYXJlYXMoZml0X0h0V3QzMF9yb2J1c3QsIHBhcnMgPSJiZXRhMCIpDQpgYGANCg0KYGBge3J9DQptY21jX2FyZWFzKGZpdF9IdFd0MzBfcm9idXN0LCBwYXJzID0gImJldGExIikNCmBgYA0KDQpgYGB7cn0NCnBhaXJzKGZpdF9IdFd0MzBfcm9idXN0LA0KICAgICAgcGFycyA9IGMoIm51IiwgInNpZ21hIiwgImJldGEwIiwgImJldGExIikpDQpgYGANCg0KDQojIyBQb3N0ZXJpb3IgcHJlZGljdGl2ZSBjaGVjaw0KDQpgYGB7cn0NCnlfc2ltX0h0V3QzMF9yb2J1c3QgPC0gc2FtcGxlc19IdFd0MzBfcm9idXN0ICU+JQ0KICAgIHNlbGVjdChzdGFydHNfd2l0aCgieV9zaW0iKSkgJT4lDQogICAgYXMubWF0cml4KCkNCmBgYA0KDQpgYGB7cn0NCmdncGxvdChIdFd0RGF0YTMwLCBhZXMoeSA9IHdlaWdodCwgeCA9IGhlaWdodF9tYykpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fYWJsaW5lKGRhdGEgPSBzYW1wbGVzX0h0V3QzMF9yb2J1c3QsDQogICAgICAgICAgICAgICAgYWVzKGludGVyY2VwdCA9IGJldGEwLCBzbG9wZSA9IGJldGExKSwNCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDEpICsNCiAgICBnZW9tX2FibGluZShkYXRhID0gc2FtcGxlc19IdFd0MzBfcm9idXN0LA0KICAgICAgICAgICAgICAgIGFlcyhpbnRlcmNlcHQgPSBtZWFuKGJldGEwKSwgc2xvcGUgPSBtZWFuKGJldGExKSksDQogICAgICAgICAgICAgICAgY29sb3IgPSAiYmx1ZSIsIGxpbmV3aWR0aCA9IDIpDQpgYGANCg0KQ29tcGFyZSB0byBzdGFuZGFyZCBsaW5lYXIgcmVncmVzc2lvbi4NCg0KYGBge3J9DQpnZ3Bsb3QoSHRXdERhdGEzMCwgYWVzKHkgPSB3ZWlnaHQsIHggPSBoZWlnaHRfbWMpKSArDQogICAgZ2VvbV9wb2ludCgpICsNCiAgICBnZW9tX2FibGluZShkYXRhID0gc2FtcGxlc19IdFd0MzBfcm9idXN0LA0KICAgICAgICAgICAgICAgIGFlcyhpbnRlcmNlcHQgPSBiZXRhMCwgc2xvcGUgPSBiZXRhMSksDQogICAgICAgICAgICAgICAgYWxwaGEgPSAwLjAxKSArDQogICAgZ2VvbV9hYmxpbmUoZGF0YSA9IHNhbXBsZXNfSHRXdDMwX3JvYnVzdCwNCiAgICAgICAgICAgICAgICBhZXMoaW50ZXJjZXB0ID0gbWVhbihiZXRhMCksIHNsb3BlID0gbWVhbihiZXRhMSkpLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gImJsdWUiLCBsaW5ld2lkdGggPSAyKSArDQogICAgZ2VvbV9zbW9vdGgobWV0aG9kID0gbG0sIGNvbG9yID0gInJlZCIsIGxpbmV3aWR0aCA9IDIpDQpgYGANCg0KYGBge3J9DQpwcGNfaW50ZXJ2YWxzKHkgPSBIdFd0RGF0YTMwJHdlaWdodCwNCiAgICAgICAgICAgICAgeCA9IEh0V3REYXRhMzAkaGVpZ2h0X21jLA0KICAgICAgICAgICAgICB5cmVwID0geV9zaW1fSHRXdDMwX3JvYnVzdCwNCiAgICAgICAgICAgICAgcHJvYiA9IDAuNjgsDQogICAgICAgICAgICAgIHByb2Jfb3V0ZXIgPSAwLjk1KQ0KYGBgDQoNCmBgYHtyfQ0KcHBjX2hpc3QoeSA9IEh0V3REYXRhMzAkd2VpZ2h0LA0KICAgICAgICAgeXJlcCA9IHlfc2ltX0h0V3QzMF9yb2J1c3RbMToxOSwgXSkNCmBgYA0KDQpgYGB7cn0NCnBwY19ib3hwbG90KHkgPSBIdFd0RGF0YTMwJHdlaWdodCwNCiAgICAgICAgICAgIHlyZXAgPSB5X3NpbV9IdFd0MzBfcm9idXN0WzE6MTAsIF0sDQogICAgICAgICAgICBub3RjaCA9IEZBTFNFKQ0KYGBgDQoNCmBgYHtyfQ0KcHBjX2RlbnNfb3ZlcmxheSh5ID0gSHRXdERhdGEzMCR3ZWlnaHQsDQogICAgICAgICAgICAgICAgIHlyZXAgPSB5X3NpbV9IdFd0MzBfcm9idXN0WzE6NTAsIF0pDQpgYGANCg0KYGBge3J9DQpwcGNfc3RhdF8yZCh5ID0gSHRXdERhdGEzMCR3ZWlnaHQsDQogICAgICAgICAgICB5cmVwID0geV9zaW1fSHRXdDMwX3JvYnVzdCkNCmBgYA0KDQoNCg0KDQojIyBUaGUgbW9kZWwgd2l0aCAzMDAgb2JzZXJ2YXRpb25zDQoNCmBgYHtyLCBjYWNoZSA9IFRSVUV9DQpmaXRfSHRXdDMwMF9yb2J1c3QgPC0gc2FtcGxpbmcoSHRXdF9yb2J1c3QsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YSA9IHN0YW5fZGF0YV8zMDAsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VlZCA9IDExMTExLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZnJlc2ggPSAwKQ0KYGBgDQoNCmBgYHtyfQ0Kc2FtcGxlc19IdFd0MzAwX3JvYnVzdCA8LSB0aWR5X2RyYXdzKGZpdF9IdFd0MzAwX3JvYnVzdCkNCnNhbXBsZXNfSHRXdDMwMF9yb2J1c3QNCmBgYA0KDQojIyBNb2RlbCBkaWFnbm9zdGljcw0KDQpgYGB7cn0NCnN0YW5fdHJhY2UoZml0X0h0V3QzMDBfcm9idXN0LA0KICAgICAgICAgICBwYXJzID0gYygibnUiLCAic2lnbWEiLCAiYmV0YTAiLCAiYmV0YTEiKSkNCmBgYA0KDQpgYGB7cn0NCm1jbWNfYWNmKGZpdF9IdFd0MzAwX3JvYnVzdCwNCiAgICAgICAgIHBhcnMgPSBjKCJudSIsICJzaWdtYSIsICJiZXRhMCIsICJiZXRhMSIpKQ0KYGBgDQoNCg0KIyMgTW9kZWwgc3VtbWFyeQ0KDQpgYGB7cn0NCnByaW50KGZpdF9IdFd0MzAwX3JvYnVzdCwNCiAgICAgIHBhcnMgPSBjKCJudSIsICJiZXRhMCIsICJiZXRhMSIsICJzaWdtYSIpKQ0KYGBgDQoNCg0KIyMgTW9kZWwgdmlzdWFsaXphdGlvbg0KDQpgYGB7cn0NCm1jbWNfYXJlYXMoZml0X0h0V3QzMDBfcm9idXN0LCBwYXJzID0gIm51IikNCmBgYA0KDQpgYGB7cn0NCm1jbWNfYXJlYXMoZml0X0h0V3QzMDBfcm9idXN0LCBwYXJzID0ic2lnbWEiKQ0KYGBgDQoNCmBgYHtyfQ0KbWNtY19hcmVhcyhmaXRfSHRXdDMwMF9yb2J1c3QsIHBhcnMgPSJiZXRhMCIpDQpgYGANCg0KYGBge3J9DQptY21jX2FyZWFzKGZpdF9IdFd0MzAwX3JvYnVzdCwgcGFycyA9ICJiZXRhMSIpDQpgYGANCg0KYGBge3J9DQpwYWlycyhmaXRfSHRXdDMwMF9yb2J1c3QsDQogICAgICBwYXJzID0gYygibnUiLCAic2lnbWEiLCAiYmV0YTAiLCAiYmV0YTEiKSkNCmBgYA0KDQoNCiMjIFBvc3RlcmlvciBwcmVkaWN0aXZlIGNoZWNrDQoNCmBgYHtyfQ0KeV9zaW1fSHRXdDMwMF9yb2J1c3QgPC0gc2FtcGxlc19IdFd0MzAwX3JvYnVzdCAlPiUNCiAgICBzZWxlY3Qoc3RhcnRzX3dpdGgoInlfc2ltIikpICU+JQ0KICAgIGFzLm1hdHJpeCgpDQpgYGANCg0KYGBge3J9DQpnZ3Bsb3QoSHRXdERhdGEzMDAsIGFlcyh5ID0gd2VpZ2h0LCB4ID0gaGVpZ2h0X21jKSkgKw0KICAgIGdlb21fcG9pbnQoKSArDQogICAgZ2VvbV9hYmxpbmUoZGF0YSA9IHNhbXBsZXNfSHRXdDMwMF9yb2J1c3QsDQogICAgICAgICAgICAgICAgYWVzKGludGVyY2VwdCA9IGJldGEwLCBzbG9wZSA9IGJldGExKSwNCiAgICAgICAgICAgICAgICBhbHBoYSA9IDAuMDEpICsNCiAgICBnZW9tX2FibGluZShkYXRhID0gc2FtcGxlc19IdFd0MzAwX3JvYnVzdCwNCiAgICAgICAgICAgICAgICBhZXMoaW50ZXJjZXB0ID0gbWVhbihiZXRhMCksIHNsb3BlID0gbWVhbihiZXRhMSkpLA0KICAgICAgICAgICAgICAgIGNvbG9yID0gImJsdWUiLCBsaW5ld2lkdGggPSAyKQ0KYGBgDQoNCkNvbXBhcmUgdG8gc3RhbmRhcmQgbGluZWFyIHJlZ3Jlc3Npb24uDQoNCmBgYHtyfQ0KZ2dwbG90KEh0V3REYXRhMzAwLCBhZXMoeSA9IHdlaWdodCwgeCA9IGhlaWdodF9tYykpICsNCiAgICBnZW9tX3BvaW50KCkgKw0KICAgIGdlb21fYWJsaW5lKGRhdGEgPSBzYW1wbGVzX0h0V3QzMDBfcm9idXN0LA0KICAgICAgICAgICAgICAgIGFlcyhpbnRlcmNlcHQgPSBiZXRhMCwgc2xvcGUgPSBiZXRhMSksDQogICAgICAgICAgICAgICAgYWxwaGEgPSAwLjAxKSArDQogICAgZ2VvbV9hYmxpbmUoZGF0YSA9IHNhbXBsZXNfSHRXdDMwMF9yb2J1c3QsDQogICAgICAgICAgICAgICAgYWVzKGludGVyY2VwdCA9IG1lYW4oYmV0YTApLCBzbG9wZSA9IG1lYW4oYmV0YTEpKSwNCiAgICAgICAgICAgICAgICBjb2xvciA9ICJibHVlIiwgbGluZXdpZHRoID0gMikgKw0KICAgIGdlb21fc21vb3RoKG1ldGhvZCA9IGxtLCBjb2xvciA9ICJyZWQiLCBsaW5ld2lkdGggPSAyKQ0KYGBgDQoNCmBgYHtyfQ0KcHBjX2ludGVydmFscyh5ID0gSHRXdERhdGEzMDAkd2VpZ2h0LA0KICAgICAgICAgICAgICB4ID0gSHRXdERhdGEzMDAkaGVpZ2h0X21jLA0KICAgICAgICAgICAgICB5cmVwID0geV9zaW1fSHRXdDMwMF9yb2J1c3QsDQogICAgICAgICAgICAgIHByb2IgPSAwLjY4LA0KICAgICAgICAgICAgICBwcm9iX291dGVyID0gMC45NSkNCmBgYA0KDQpgYGB7cn0NCnBwY19oaXN0KHkgPSBIdFd0RGF0YTMwMCR3ZWlnaHQsDQogICAgICAgICB5cmVwID0geV9zaW1fSHRXdDMwMF9yb2J1c3RbMToxOSwgXSkNCmBgYA0KDQpgYGB7cn0NCnBwY19ib3hwbG90KHkgPSBIdFd0RGF0YTMwMCR3ZWlnaHQsDQogICAgICAgICAgICB5cmVwID0geV9zaW1fSHRXdDMwMF9yb2J1c3RbMToxMCwgXSwNCiAgICAgICAgICAgIG5vdGNoID0gRkFMU0UpDQpgYGANCg0KYGBge3J9DQpwcGNfZGVuc19vdmVybGF5KHkgPSBIdFd0RGF0YTMwMCR3ZWlnaHQsDQogICAgICAgICAgICAgICAgIHlyZXAgPSB5X3NpbV9IdFd0MzAwX3JvYnVzdFsxOjUwLCBdKQ0KYGBgDQoNCmBgYHtyfQ0KcHBjX3N0YXRfMmQoeSA9IEh0V3REYXRhMzAwJHdlaWdodCwNCiAgICAgICAgICAgIHlyZXAgPSB5X3NpbV9IdFd0MzAwX3JvYnVzdCkNCmBgYA==